package com.netty.promise;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.nio.charset.StandardCharsets;

/**
 * @author renyitong
 * @version 1.0.0
 * @createTime 2023年08月10日
 * @Description
 */
public class ProNettyServer {

    public static void main(String[] args) throws InterruptedException {
        // 这里我们使用NioEventLoopGroup实现类即可，创建BossGroup和WorkerGroup
        // 当然还有EpollEventLoopGroup，但是仅支持Linux，这是Netty基于Linux底层Epoll单独编写的一套本地实现，没有使用NIO那套
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // 创建服务端启动引导类
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 链式编写，很棒
        bootstrap
                .group(bossGroup, workerGroup)   // 指定事件循环组
                .channel(NioServerSocketChannel.class)  // 指定为NIO的ServerSocketChannel
                .childHandler(new ChannelInitializer<SocketChannel>() { // 注意，这里的SocketChannel不是我们NIO里面的，是Netty的
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        //获取流水线，当我们需要处理客户端的数据时，实际上是像流水线一样在处理，这个流水线上可以有很多Handler
                        channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {  // 添加一个Handler，这里使用ChannelInboundHandlerAdapter
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                // ctx是上下文，msg是收到的消息，默认以ByteBuf形式（也可以是其他形式，后面再说）
                                ByteBuf byteBuf = (ByteBuf) msg;
                                System.out.println(Thread.currentThread().getName() + " 接收到了客户端发送的数据: " + byteBuf.toString(StandardCharsets.UTF_8));

                                ChannelPromise promise = ctx.newPromise();
                                System.out.println(promise.isSuccess());

                                // 通过上下文可以直接将数据发送给客户端，注意writeAndFlush才能让客户端立即的收到
                                ctx.writeAndFlush(Unpooled.wrappedBuffer("已收到! ".getBytes()), promise);
                                promise.sync(); // 同步等待一下
                                System.out.println(promise.isSuccess());
                            }
                        });
                    }
                });

        // 最后绑定端口，启动
        ChannelFuture future = bootstrap.bind(8080);

        //直接添加监听器，当任务完成时自动执行，但是注意执行也是异步的，不是在当前线程
        future.addListener(f -> {
            System.out.println("服务端启动状态：" + future.isDone());
            System.out.println("我是服务端启动完成之后要做的事情！");
        });

//        future.sync(); // 让当前线程同步等待任务完成
//        System.out.println("服务端启动状态："+future.isDone());
//        System.out.println("我是服务端启动完成之后要做的事情！");

    }


}
